#define CROW_MAIN // 生成 main 函数
#include "crow.h" // 或 crow_all.h
#include "nlohmann/json.hpp"

#include <string>
#include <vector>
#include <mutex>
#include <chrono>
#include <iomanip>
#include <sstream>
#include <iostream>
#include <fstream> // 使用 C++ 文件流替代 C-style I/O
#include <algorithm> // 用于 std::sort, std::max
#include <limits>    // 用于 numeric_limits

// 使用 nlohmann::json 简化 JSON 操作
using json = nlohmann::json;

// --- 配置 ---
const std::string LEADERBOARD_FILE = "leaderboard.json";
const size_t MAX_LEADERBOARD_SIZE = 100; // 与 Python 版本一致

// --- 全局状态与同步 ---
std::mutex leaderboard_mutex; // 保护文件访问

// --- CORS 中间件 ---
struct CorsMiddleware {
    struct context {
        // 中间件上下文，如果需要跨 before_handle 和 after_handle 传递数据
    };

    void before_handle(crow::request& req, crow::response& res, context& /*ctx*/) {
        // 预检请求 (OPTIONS)
        if (req.method == crow::HTTPMethod::Options) {
            res.add_header("Access-Control-Allow-Origin", "*"); // 允许所有源
            res.add_header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
            res.add_header("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With");
            // res.add_header("Access-Control-Max-Age", "86400"); // 可选：预检请求结果的缓存时间 (秒)
            res.code = 204; // No Content
            res.end(); // 结束请求处理，不传递给后续路由
            return;
        }
    }

    void after_handle(crow::request& /*req*/, crow::response& res, context& /*ctx*/) {
        // 为所有非 OPTIONS 响应添加 Allow-Origin (如果尚未设置)
        // 确保即使路由处理程序没有显式设置，CORS 头部也会被添加
        if (res.get_header_value("Access-Control-Allow-Origin").empty()) {
            res.add_header("Access-Control-Allow-Origin", "*"); // 允许所有源
        }
        // 你也可以在这里添加其他通用的 CORS 头部，如果它们适用于所有响应
    }
};

// --- 辅助函数 ---

// 获取当前时间的 ISO 8601 格式字符串 (UTC)
std::string getCurrentTimestampISO8601() {
    auto now = std::chrono::system_clock::now();
    auto itt = std::chrono::system_clock::to_time_t(now);
    std::ostringstream ss;
    // 使用 std::gmtime 获取 UTC 时间
    // std::put_time 在某些 MinGW 版本可能有问题，可以手动格式化
    // ss << std::put_time(std::gmtime(&itt), "%Y-%m-%dT%H:%M:%SZ");
    std::tm utc_tm = *std::gmtime(&itt);
    ss << std::setfill('0')
       << std::setw(4) << utc_tm.tm_year + 1900 << '-'
       << std::setw(2) << utc_tm.tm_mon + 1 << '-'
       << std::setw(2) << utc_tm.tm_mday << 'T'
       << std::setw(2) << utc_tm.tm_hour << ':'
       << std::setw(2) << utc_tm.tm_min << ':'
       << std::setw(2) << utc_tm.tm_sec << 'Z';
    return ss.str();
}

// 从 JSON 文件加载排行榜数据 (使用 C++ 文件流)
json loadScores() {
    json scores_data = json::array(); // 默认为空数组
    std::ifstream file(LEADERBOARD_FILE);

    if (file.is_open()) {
        try {
            // 尝试直接从文件流解析 JSON
            file >> scores_data;
            // 确保解析结果是 JSON 数组
            if (!scores_data.is_array()) {
                std::cerr << "警告: " << LEADERBOARD_FILE << " 内容解析后不是有效的 JSON 数组，将使用空数组。" << std::endl;
                scores_data = json::array();
            }
        } catch (json::parse_error& e) {
            // 文件内容为空或无效 JSON 时会抛出异常
            if (file.peek() == std::ifstream::traits_type::eof()) {
                // 文件为空，返回空数组是正常的
                scores_data = json::array();
            } else {
                std::cerr << "错误: 解析 " << LEADERBOARD_FILE << " 失败: " << e.what() << std::endl;
                scores_data = json::array(); // 解析出错时返回空数组
            }
        }
        file.close(); // 关闭文件
    } else {
        // 文件不存在或无法打开，假定为空列表 (首次运行正常)
        // std::cout << "信息: " << LEADERBOARD_FILE << " 未找到或无法打开。将视为空排行榜。" << std::endl;
        scores_data = json::array();
    }
    return scores_data;
}

// 将排行榜数据保存到 JSON 文件 (使用 C++ 文件流)
bool saveScores(const json& scores_data) {
    if (!scores_data.is_array()) {
        std::cerr << "错误: 尝试将非数组类型的 JSON 数据保存到 " << LEADERBOARD_FILE << std::endl;
        return false;
    }

    std::ofstream file(LEADERBOARD_FILE, std::ios::trunc); // 打开并清空文件
    if (file.is_open()) {
        try {
            // 将 JSON 对象序列化为带缩进的 UTF-8 字符串并写入文件
            file << std::setw(4) << scores_data << std::endl; // setw(4) 提供缩进
            file.close(); // 关闭文件
            return file.good(); // 检查写入操作是否成功
        } catch (const std::exception& e) {
            std::cerr << "错误: 写入 " << LEADERBOARD_FILE << " 时发生异常: " << e.what() << std::endl;
            file.close(); // 尝试关闭文件
            return false;
        }
    } else {
        std::cerr << "错误: 无法打开 " << LEADERBOARD_FILE << " 进行写入。" << std::endl;
        return false;
    }
}

// --- 主应用程序 ---
int main() {
    crow::App<CorsMiddleware> app;

    // --- API 路由定义 ---

    // GET /api/scores - 获取排行榜
    CROW_ROUTE(app, "/api/scores").methods(crow::HTTPMethod::Get)
    ([](const crow::request& req) {
        int limit = 10; // 默认限制
        // 尝试获取 limit 查询参数
        const char* limit_str = req.url_params.get("limit");
        if (limit_str) {
            try {
                int requested_limit = std::stoi(limit_str);
                if (requested_limit > 0) {
                    limit = requested_limit;
                } else {
                     std::cerr << "警告: 无效的 'limit' 参数值 '" << limit_str << "' (必须为正整数)，使用默认值 " << limit << std::endl;
                }
            } catch (const std::invalid_argument& e) {
                std::cerr << "警告: 无效的 'limit' 参数值 '" << limit_str << "' (非整数)，使用默认值 " << limit << std::endl;
            } catch (const std::out_of_range& e) {
                 std::cerr << "警告: 'limit' 参数值 '" << limit_str << "' 超出范围，使用默认值 " << limit << std::endl;
            }
        }

        std::vector<json> sorted_scores_vec;
        { // 限制锁的作用域
            std::lock_guard<std::mutex> lock(leaderboard_mutex);
            json scores = loadScores();

            // 检查是否为数组，如果不是（例如加载失败），直接返回空数组
            if (!scores.is_array()) {
                crow::response res(json::array().dump());
                res.add_header("Content-Type", "application/json; charset=utf-8");
                return res;
            }

            // 将 JSON 数组复制到 std::vector 以便排序
            // 直接在 nlohmann::json 数组上排序有时会遇到迭代器失效问题，vector 更安全
            for(const auto& score_item : scores) {
                // 基本检查，确保是对象并且包含 score 字段
                if (score_item.is_object() && score_item.contains("score") && score_item["score"].is_number()) {
                    sorted_scores_vec.push_back(score_item);
                } else {
                     std::cerr << "警告: 跳过无效的排行榜记录: " << score_item.dump() << std::endl;
                }
            }
        } // 锁在这里释放，后续排序和限制操作在 vector 上进行

        // 排序 (按分数降序)
        std::sort(sorted_scores_vec.begin(), sorted_scores_vec.end(),
                  [](const json& a, const json& b) {
                      // 安全地获取分数，如果字段不存在或类型错误，则视为最低分
                      int score_a = a.value("score", std::numeric_limits<int>::min());
                      int score_b = b.value("score", std::numeric_limits<int>::min());
                      return score_a > score_b; // 降序
                  });

        // 应用 limit
        if (sorted_scores_vec.size() > static_cast<size_t>(limit)) {
            sorted_scores_vec.resize(limit);
        }

        // 将排序和限制后的 vector 转换回 JSON 数组
        json limited_scores = json(sorted_scores_vec);

        crow::response res(limited_scores.dump());
        res.add_header("Content-Type", "application/json; charset=utf-8");
        return res;
    });

    // POST /api/scores - 提交新分数
    CROW_ROUTE(app, "/api/scores").methods(crow::HTTPMethod::Post)
    ([](const crow::request& req) {
        json score_input;
        try {
            score_input = json::parse(req.body);
        } catch (json::parse_error& e) {
            json error_res = {{"error", "无效的 JSON 格式: " + std::string(e.what())}};
            return crow::response(400, error_res.dump());
        }

        // --- 输入验证 ---
        json error_details = json::object(); // 用于收集多个验证错误

        // 验证 playerName
        if (!score_input.contains("playerName") || !score_input["playerName"].is_string()) {
            error_details["playerName"] = "Player name is required and must be a string.";
        } else {
            std::string player_name = score_input["playerName"];
            if (player_name.empty() || std::all_of(player_name.begin(), player_name.end(), ::isspace)) {
                 error_details["playerName"] = "Player name cannot be empty or just whitespace.";
            } else if (player_name.length() > 50) {
                error_details["playerName"] = "Player name cannot exceed 50 characters.";
            }
            // 注意：C++ 标准库没有内置 trim，这里只检查空和长度
        }

        // 验证 score
        if (!score_input.contains("score")) {
            error_details["score"] = "Score is required.";
        } else if (!score_input["score"].is_number_integer()) {
             error_details["score"] = "Score must be an integer.";
        } else {
            int score_val = score_input["score"];
            if (score_val < 0) {
                error_details["score"] = "Score must be a non-negative integer.";
            }
        }

        // 如果有验证错误，返回 400
        if (!error_details.empty()) {
            json error_res = {{"error", "Invalid input data"}, {"details", error_details}};
            return crow::response(400, error_res.dump());
        }

        // --- 处理分数 ---
        json new_score_record;
        { // 限制锁的作用域
            std::lock_guard<std::mutex> lock(leaderboard_mutex);
            json scores = loadScores();

            // 确保加载后仍是数组
             if (!scores.is_array()) {
                 json error_res = {{"error", "Server error: Could not load leaderboard data correctly."}};
                 return crow::response(500, error_res.dump());
             }

            // 创建新记录
            new_score_record["playerName"] = score_input["playerName"]; // 已验证为非空字符串
            new_score_record["score"] = score_input["score"];         // 已验证为非负整数
            new_score_record["timestamp"] = getCurrentTimestampISO8601();

            scores.push_back(new_score_record);

            // 可选：在保存前排序并限制大小
            std::sort(scores.begin(), scores.end(),
                      [](const json& a, const json& b) {
                           // 确保排序时处理可能的无效记录
                           int score_a = 0, score_b = 0;
                           if (a.is_object() && a.contains("score") && a["score"].is_number()) score_a = a["score"];
                           if (b.is_object() && b.contains("score") && b["score"].is_number()) score_b = b["score"];
                           return score_a > score_b;
                      });

            if (scores.size() > MAX_LEADERBOARD_SIZE) {
                // 从末尾删除多余的记录 (分数最低的)
                 scores.erase(scores.begin() + MAX_LEADERBOARD_SIZE, scores.end());
            }


            // 保存更新后的排行榜
            if (!saveScores(scores)) {
                json error_res = {{"error", "Server error: Could not save score data."}};
                return crow::response(500, error_res.dump());
            }
        } // 锁在这里释放

        // 返回成功创建的记录和 201 状态码
        crow::response res(201, new_score_record.dump());
        res.add_header("Content-Type", "application/json; charset=utf-8");
        return res;
    });

    // --- 运行服务器 ---
    #ifdef _WIN32
        system("chcp 65001 > nul");
        std::cout << "信息: (Windows) 尝试将控制台代码页设置为 UTF-8 (65001)。" << std::endl;
    #endif

    std::cout << "服务器正在启动，监听端口 5000..." << std::endl;
    app.port(5000)        // 设置端口为 5000
       .multithreaded()   // 启用多线程
       .run();

    return 0;
}
